﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Xml;
using System.Text;
using WMM.Tapioca.Taxonomy;
using WMM.Tapioca.Instance;
using WMM.Tapioca.Utilities;
using System.Xml.Linq;
using System.Xml.Schema;

namespace WMM.Tapioca.Linkbase
{
	/// <summary>
    /// XBRL 2.1 Specification 5.2
	/// Represents a linkbase document. A linkbase document is an XML document with a root
	/// element called linkbase. Linkbase documents are referenced in linkbaseRef elements in
	/// XBRL schemas.
    /// The extended links in a taxonomy provide additional information about concepts by 
    /// expressing relationships between concepts (inter-concept relationships) or associating
    /// concepts with documentation about their meaning. 
	/// </summary>
    public class LinkbaseDocument : XbrlDocument
    {
        private XElement linkbaseElement;

        private string roleLinkbaseRef;

        /// <summary>
        /// Represents a role of link:linkbaseRef.
        /// </summary>
        public string RoleLinkbaseRef
        {
            get { return roleLinkbaseRef; }
            set { roleLinkbaseRef = value; }
        }

        private List<ExtendedLink> extendedLinks;

        /// <summary>
        /// Represents a list of ExtendedLink objects.
        /// </summary>
        public List<ExtendedLink> ExtendedLinks
        {
            get { return extendedLinks; }
            set { extendedLinks = value; }
        }

        /// <summary>
        /// The instance that references this linkbase document.
        /// </summary>
        public InstanceDocument Instance
        {
            get;
            private set;
        }

		/// <summary>
		/// The schema that references this linkbase document.
		/// </summary>
		public XmlSchema Schema
		{
			get;
			private set;
		}


        /// <summary>
        /// Constructor with linkbase file loaded first.
        /// </summary>
        public LinkbaseDocument(XbrlDocument xbrlDocument, XmlUrlResolver resolver)
        {
            this.extendedLinks = new List<ExtendedLink>();
            this.Schema = null;
            roleLinkbaseRef = "";

            this.FileName = xbrlDocument.FileName;
            this.PathFile = xbrlDocument.PathFile;
            this.ThisXDocument = xbrlDocument.ThisXDocument;
            this.DocType = this.ThisXDocument.Root.Name.LocalName;
            this.targetNamespace = xbrlDocument.ThisXDocument.Root.Name.NamespaceName;
            this.namespaceManager = xbrlDocument.ThisXDocument.CreateNamespaceManager();

            ReadLinkbaseNode();
            Dts = new DTS(this, resolver);
        }


        ///// <summary>
        ///// Constructor with linkbase referenced in linkbaseRef element in Schema.
        ///// </summary>
        //public LinkbaseDocument(DTS dtsXbrl, TaxonomySchema containingXbrlSchema, string baseAttr, string linkbaseFilename, string role, XmlUrlResolver resolver)
        //    : base(dtsXbrl, linkbaseFilename, containingXbrlSchema.ThisXDocument.Root.BaseUri, baseAttr, resolver)
        //{
        //    this.extendedLinks = new List<ExtendedLink>();        
        //    this.Schema = containingXbrlSchema;
        //    roleLinkbaseRef = role;
        //    ReadLinkbaseNode();
        //}


        /// <summary>
        /// Constructor with linkbase referenced in linkbaseRef element in Schema.
        /// </summary>
        public LinkbaseDocument(DTS dtsXbrl, XmlSchema containingXbrlSchema, string baseAttr, string linkbaseFilename, string role, XmlUrlResolver resolver)
            : base(dtsXbrl, linkbaseFilename, containingXbrlSchema != null ? containingXbrlSchema.SourceUri : "", baseAttr, resolver)
        {
            this.extendedLinks = new List<ExtendedLink>();
            this.Schema = containingXbrlSchema;
            roleLinkbaseRef = role;
            ReadLinkbaseNode();
        }


        /// <summary>
        /// Constructor with linkbase referenced in linkbaseRef element in instance.
        /// </summary>
        internal LinkbaseDocument(DTS dtsXbrl, InstanceDocument containingInstance, string baseAttr, string linkbaseFilename, string role, XmlUrlResolver resolver)
            : base(dtsXbrl, linkbaseFilename, containingInstance.ThisXDocument.Root.BaseUri, baseAttr, resolver)
        {
            this.extendedLinks = new List<ExtendedLink>();                    
            this.Instance = containingInstance;
            roleLinkbaseRef = role;
            ReadLinkbaseNode();
        }

        // This constructor is used with linkbase contained in schema.
        internal LinkbaseDocument(DTS dtsXbrl, XmlSchema containingXbrlSchema, XmlNode linkbaseNode, string role, XmlUrlResolver resolver)
        {
            Dts = dtsXbrl;
            this.extendedLinks = new List<ExtendedLink>();
            this.Schema = containingXbrlSchema;
            roleLinkbaseRef = role;
            ThisXDocument = XDocument.Load(new XmlNodeReader(linkbaseNode)); 
            CreateNamespaceManager();
            ReadLinkbaseNode();
        }


        private void ReadLinkbaseNode()
        {
            linkbaseElement = ThisXDocument.Root;

            foreach (XElement currentElement in linkbaseElement.Elements())
            {
                XNamespace ns = Constants.XLINKUri;

                string type = (string)currentElement.Attribute(ns + "type") ?? string.Empty;

                if (type.Equals("extended"))
                {
                    this.ExtendedLinks.Add(new ExtendedLink(currentElement, linkbaseElement, this));
                }
            }
        }


    }
}
